﻿
using System;
using System.Drawing;
using System.IO;
namespace DZParallelLib.DZImage
{
    /// <summary>
    /// Some basic image utilities for a DZ image or collection, etc.
    /// </summary>
    internal class DZImageBase
    {
        /// <summary>
        /// Create the image base.
        /// </summary>
        /// <param name="tileSize">Size of a square tile in pixels. Defaults to 256.</param>
        public DZImageBase()
        {
        }

        /// <summary>
        /// Size of a tile in pixels
        /// </summary>
        public ulong TileSize { get; protected set; }

        /// <summary>
        /// Width of the complete image, in pixels
        /// </summary>
        public ulong Width { get; protected set; }

        /// <summary>
        /// Width fo the image, in pixels
        /// </summary>
        public ulong Height { get; protected set; }

        /// <summary>
        /// The overlap of images. Often zero in my observation
        /// </summary>
        public ulong Overlap { get; protected set; }

        /// <summary>
        /// The number of levels this image contains
        /// </summary>
        public uint NumberOfLevels { get; protected set; }

        private ulong _cachedMaxDimension = 0;
        /// <summary>
        /// Return the maximum dimension of the Width and Height properties.
        /// </summary>
        public ulong MaxDimension
        {
            get
            {
                if (_cachedMaxDimension == 0)
                    _cachedMaxDimension = Math.Max(Width, Height);
                return _cachedMaxDimension;
            }
        }

        /// <summary>
        /// Returns the calculated dimensions of the image for a particular level
        /// </summary>
        /// <param name="level"></param>
        /// <returns>Return the size, in pixels, of the image at this level</returns>
        public Size SizeOfImageInLevel(uint level)
        {
            if (level >= NumberOfLevels)
                throw new InvalidOperationException(string.Format("Requesting size for level {0}, but highest level for this image is {1}.", level, NumberOfLevels));

            var scale = Math.Pow(0.5, NumberOfLevels - 1 - level);
            var result = new Size((int)Math.Ceiling(Width * scale), (int)Math.Ceiling(Height * scale));
            return result;
        }

        /// <summary>
        /// Return the level that is the first one larger than the given minimum size.
        /// </summary>
        /// <param name="minimumSize"></param>
        /// <returns>The first level that has a dimension larger than minimumSize</returns>
        /// <remarks>
        /// Level is a zero based number!
        /// </remarks>
        public uint LevelThatContainsSize(ulong minimumSize)
        {
            if (minimumSize > MaxDimension)
                throw new InvalidOperationException(string.Format("Requested image of size {0} pixels, but the image is only {1}x{2} pixels.", minimumSize, Width, Height));

            var proposed = (NumberOfLevels - 1) - (uint)Math.Floor(Math.Log(MaxDimension, 2) - Math.Log(minimumSize, 2));

            // There are some issues having to do with rounding of pixels, so we can check that quickly.
            if (proposed == 0)
                return proposed;

            var sizeDownOne = SizeOfImageInLevel(proposed - 1);
            if ((ulong)Math.Max(sizeDownOne.Width, sizeDownOne.Height) >= minimumSize)
                return proposed - 1;
            return proposed;
        }

        /// <summary>
        /// Return an image level descriptor for this image at a particular level.
        /// </summary>
        /// <param name="level"></param>
        /// <returns></returns>
        public DZImageLevelDescriptor ImageDescriptorAtLevel(uint level)
        {
            var size = SizeOfImageInLevel(level);
            return new DZImageLevelDescriptor(size,
                TileSize,
                Overlap
                );
        }
    }
}
